home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / src / smailconf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-16  |  27.4 KB  |  1,015 lines

  1. /* @(#)src/smailconf.c    1.15 9/16/92 09:10:36 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * smailconf.c:
  13.  *    loading and processing for the configuration files
  14.  *
  15.  *    external functions: read_config_file, read_standard_file,
  16.  *                fill_attributes, find_attribute,
  17.  *                add_config_stat, is_newconf, make_lib_fn
  18.  */
  19. #ifdef    STANDALONE
  20. # ifdef    scs
  21. #  define void int
  22. # endif    /* scs */
  23. #endif    /* STANDALONE */
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include "defs.h"
  29. #include "smail.h"
  30. #include "smailconf.h"
  31. #include "parse.h"
  32. #include "main.h"
  33. #include "exitcodes.h"
  34. #include "dys.h"
  35. #ifndef DEPEND
  36. # include "extern.h"
  37. # include "debug.h"
  38. #endif
  39.  
  40. /* functions local to this file */
  41. static void print_config_help();
  42. static void print_config_all();
  43. static void print_version_banner();
  44.  
  45. /* types local to this file */
  46. /*
  47.  * config_stat_list is used by add_config_stat() and is_newconf() to
  48.  * determine if any configuration files have changed.  Optional config
  49.  * files which do not exist have a 0 stored in the mtime field.
  50.  */
  51. struct config_stat {
  52.     struct config_stat *succ;
  53.     char    *fn;            /* name of config file */
  54.     time_t  mtime;            /* time of last mod */
  55.     dev_t   dev;            /* device file resides on */
  56.     ino_t   ino;            /* inode number for file */
  57. } *config_stat_list = NULL;
  58.  
  59. /* define the attributes which may be in the config file */
  60. static struct attr_table conf_attributes[] = {
  61.     { "auth_domains", t_string, NULL, (tup *)&auth_domains, 0 },
  62.     { "auth_domain", t_string, NULL, (tup *)&auth_domains, 0 },
  63.     { "auto_mkdir", t_boolean, NULL, (tup *)&auto_mkdir, 0 },
  64.     { "auto_mkdir_mode", t_int, NULL, (tup *)&auto_mkdir_mode, 0 },
  65.     { "config_file", t_string, NULL, (tup *)&config_file, 0 },
  66.     { "console", t_string, NULL, (tup *)&cons_fn, 0 },
  67.     { "copying_file", t_string, NULL, (tup *)©ing_file, 0 },
  68.     { "date_field", t_string, NULL, (tup *)&date_field, 0 },
  69.     { "delivery_mode", t_string, NULL, (tup *)&delivery_mode_string, 0 },
  70.     { "director_file", t_string, NULL, (tup *)&director_file, 0 },
  71.     { "domains", t_string, NULL, (tup *)&visible_domains, 0 },
  72.     { "domain", t_string, NULL, (tup *)&visible_domains, 0 },
  73.     { "visible_domains", t_string, NULL, (tup *)&visible_domains, 0 },
  74.     { "visible_domain", t_string, NULL, (tup *)&visible_domains, 0 },
  75.     { "error_copy_postmaster", t_boolean, NULL,
  76.       (tup *)&error_copy_postmaster, 0 },
  77.     { "flock_mailbox", t_boolean, NULL, (tup *)&flock_mailbox, 0 },
  78.     { "fnlock_interval", t_int, NULL, (tup *)&fnlock_interval, 0 },
  79.     { "fnlock_mode", t_int, NULL, (tup *)&fnlock_mode, 0 },
  80.     { "fnlock_retries", t_int, NULL, (tup *)&fnlock_retries, 0 },
  81.     { "from_field", t_string, NULL, (tup *)&from_field, 0 },
  82.     { "grades", t_string, NULL, (tup *)&grades, 0 },
  83.     { "hit_table_len", t_int, NULL, (tup *)&hit_table_len, 0 },
  84.     { "host_lock_timeout", t_interval, NULL, (tup *)&host_lock_timeout, 0 },
  85.     { "hostnames", t_string, NULL, (tup *)&hostnames, 0 },
  86.     { "hostname", t_string, NULL, (tup *)&hostnames, 0 },
  87.     { "lock_by_name", t_boolean, NULL, (tup *)&lock_by_name, 0 },
  88.     { "lock_mode", t_int, NULL, (tup *)&lock_mode, 0 },
  89.     { "log_mode", t_int, NULL, (tup *)&log_mode, 0 },
  90.     { "logfile", t_string, NULL, (tup *)&log_fn, 0 },
  91.     { "max_hop_count", t_int, NULL, (tup *)&max_hop_count, 0 },
  92.     { "max_load_ave", t_double, NULL, (tup *)&max_load_ave, 0 },
  93.     { "max_message_size", t_long, NULL, (tup *)&max_message_size, 0 },
  94.     { "message_buf_size", t_int, NULL, (tup *)&message_bufsiz, 0 },
  95.     { "message_id_field", t_string, NULL, (tup *)&message_id_field, 0 },
  96.     { "message_log_mode", t_int, NULL, (tup *)&message_log_mode, 0 },
  97.     { "method_dir", t_string, NULL, (tup *)&method_dir, 0 },
  98.     { "more_hostnames", t_string, NULL, (tup *)&more_hostnames, 0 },
  99.     { "gateway_names", t_string, NULL, (tup *)&more_hostnames, 0 },
  100.     { "nobody", t_string, NULL, (tup *)&nobody, 0 },
  101.     { "open_interval", t_int, NULL, (tup *)&open_interval, 0 },
  102.     { "open_retries", t_int, NULL, (tup *)&open_retries, 0 },
  103.     { "paniclog", t_string, NULL, (tup *)&panic_fn, 0 },
  104.     { "postmaster_address", t_string, NULL, (tup *)&postmaster_address, 0 },
  105.     { "postmaster", t_string, NULL, (tup *)&postmaster_address, 0 },
  106.     { "primary_name", t_string, NULL, (tup *)&primary_name, 0 },
  107.     { "qualify_file", t_string, NULL, (tup *)&qualify_file, 0 },
  108.     { "queue_only", t_boolean, NULL, (tup *)&queue_only, 0 },
  109.     { "received_field", t_string, NULL, (tup *)&received_field, 0 },
  110.     { "require_configs", t_boolean, NULL, (tup *)&require_configs, 0 },
  111.     { "retry_duration", t_interval, NULL, (tup *)&retry_duration, 0 },
  112.     { "retry_file", t_string, NULL, (tup *)&retry_file, 0 },
  113.     { "retry_interval", t_interval, NULL, (tup *)&retry_interval, 0 },
  114.     { "return_path_field", t_string, NULL, (tup *)&return_path_field, 0 },
  115.     { "router_file", t_string, NULL, (tup *)&router_file, 0 },
  116.     { "second_config_file", t_string, NULL, (tup *)&second_config_file, 0 },
  117.     { "sender_env_variable", t_string, NULL, (tup *)&sender_env_variable, 0 },
  118.     { "smail", t_string, NULL, (tup *)&smail, 0 },
  119.     { "smail_lib_dir", t_string, NULL, (tup *)&smail_lib_dir, 0 },
  120.     { "smail_util_dir", t_string, NULL, (tup *)&smail_util_dir, 0 },
  121.     { "smart_path", t_string, NULL, (tup *)&smart_path, 0 },
  122.     { "smart_transport", t_string, NULL, (tup *)&smart_transport, 0 },
  123.     { "smart_user", t_string, NULL, (tup *)&smart_user, 0 },
  124.     { "smtp_banner", t_string, NULL, (tup *)&smtp_banner, 0 },
  125.     { "smtp_debug", t_boolean, NULL, (tup *)&smtp_debug, 0 },
  126.     { "smtp_accept_max", t_int, NULL, (tup *)&smtp_accept_max, 0 },
  127.     { "smtp_accept_queue", t_int, NULL, (tup *)&smtp_accept_queue, 0 },
  128.     { "smtp_receive_command_timeout", t_interval, NULL,
  129.       (tup *)&smtp_receive_command_timeout, 0 },
  130.     { "smtp_receive_message_timeout", t_interval, NULL,
  131.       (tup *)&smtp_receive_message_timeout, 0 },
  132.     { "spool_dirs", t_string, NULL, (tup *)&spool_dirs, 0 },
  133.     { "spool_dir", t_string, NULL, (tup *)&spool_dir, 0 },
  134.     { "spool_grade", t_char, NULL, (tup *)&spool_grade, 0 },
  135.     { "spool_mode", t_int, NULL, (tup *)&spool_mode, 0 },
  136.     { "switch_percent_and_bang", t_boolean, NULL,
  137.       (tup *)&switch_percent_and_bang, 0 },
  138.     { "transport_file", t_string, NULL, (tup *)&transport_file, 0 },
  139.     { "trusted", t_string, NULL, (tup *)&trusted, 0 },
  140.     { "trusted_users", t_string, NULL, (tup *)&trusted, 0 },
  141.     { "trusted_user", t_string, NULL, (tup *)&trusted, 0 },
  142.     { "trusted_groups", t_string, NULL, (tup *)&trusted_groups, 0 },
  143.     { "trusted_group", t_string, NULL, (tup *)&trusted_groups, 0 },
  144. #ifdef GLOTZNET
  145.     { "tzoffset", t_int, NULL, (tup *)&tzoffset, 0 },
  146.     { "tznodst", t_boolean, NULL, (tup *)&tznodst, 0 },
  147. #endif /* GLOTZNET */
  148.     { "uucp_name", t_string, NULL, (tup *)&uucp_name, 0 },
  149.     { "version", t_infoproc, NULL, (tup *)version, 0 },
  150.     { "visible_name", t_string, NULL, (tup *)&visible_name, 0 },
  151. };
  152. struct attr_table *end_conf_attributes = ENDTABLE(conf_attributes);
  153.  
  154.  
  155. /*
  156.  * read_config_file - read a config file and fill in conf_attributes
  157.  *
  158.  * return an error message or NULL (if no error).
  159.  */
  160. char *
  161. read_config_file(fn)
  162.     char *fn;                /* name of a config file */
  163. {
  164.     char *entry;            /* entry found by read_entry */
  165.     FILE *f;                /* input file */
  166.     struct stat statbuf;
  167.  
  168.     if (fn == NULL || EQ(fn, "-")) {
  169.     /* a name of `-' turns off use of the external file */
  170.     return NULL;
  171.     }
  172.  
  173.     f = fopen(fn, "r");
  174.     if (f == NULL) {
  175.     if (require_configs) {
  176.         return xprintf("%s: %s", fn, strerrno());
  177.     }
  178.  
  179.     add_config_stat(fn, (struct stat *)NULL);
  180.     return NULL;
  181.     }
  182.  
  183.     (void)fstat(fileno(f), &statbuf);
  184.     add_config_stat(fn, &statbuf);
  185.  
  186.     /*
  187.      * read all of the entries in the config file
  188.      */
  189.     while (entry = read_entry(f)) {
  190.     char *error;
  191.     struct attr_table *conf_attr;
  192.     struct attribute *attr = parse_config(entry, &error);
  193.  
  194.     if (attr == NULL) {
  195.         return xprintf("%s: parse error: %s", fn, error);
  196.     }
  197.     conf_attr = find_attribute(attr->name, conf_attributes,
  198.                    end_conf_attributes);
  199.     if (conf_attr == NULL) {
  200.         return xprintf("%s: unknown attribute: %s",
  201.                fn, attr->name);
  202.     }
  203.     conf_attr->value = attr->value;
  204.  
  205.     if (conf_attr->type == t_boolean) {
  206.         /* make sure boolean types are given as booleans */
  207.         if (attr->value != on && attr->value != off) {
  208.         return xprintf("%s: boolean attribute %s has non-boolean form",
  209.                    fn, attr->name);
  210.         }
  211.     } else {
  212.         /* make sure non-boolean types aren't given as booleans */
  213.         if ((attr->value == on &&
  214.          conf_attr->type != t_proc) ||
  215.         (attr->value == off &&
  216.          conf_attr->type != t_string &&
  217.          conf_attr->type != t_int &&
  218.          conf_attr->type != t_long &&
  219.          conf_attr->type != t_interval &&
  220.          conf_attr->type != t_double &&
  221.          conf_attr->type != t_proc))
  222.         {
  223.         return xprintf("%s: non-boolean attribute %s has boolean form",
  224.                    fn, attr->name);
  225.         }
  226.     }
  227.  
  228.     switch (conf_attr->type) {
  229.     case t_string:
  230.         if (attr->value == off) {
  231.         conf_attr->uptr->v_string = NULL;
  232.         } else {
  233.         conf_attr->uptr->v_string = attr->value;
  234.         }
  235.         break;
  236.  
  237.     case t_boolean:
  238.         conf_attr->uptr->v_boolean =
  239.         (int)c_atol(attr->value, &error);
  240.         break;
  241.  
  242.     case t_char:
  243.         if (strlen(attr->value) != 1) {
  244.         return xprintf("%s: bad character constant for attribute %s",
  245.                    fn, attr->name);
  246.         }
  247.         conf_attr->uptr->v_char = attr->value[0];
  248.         break;
  249.  
  250.     case t_int:
  251.         error = NULL;
  252.         conf_attr->uptr->v_int = (int)c_atol(attr->value, &error);
  253.  
  254.         if (error) {
  255.         return xprintf("%s: attribute %s: %s",
  256.                    fn, attr->name, error);
  257.         }
  258.         break;
  259.  
  260.     case t_long:
  261.         error = NULL;
  262.         conf_attr->uptr->v_long = c_atol(attr->value, &error);
  263.  
  264.         if (error) {
  265.         return xprintf("%s: attribute %s: %s",
  266.                    fn, attr->name, error);
  267.         }
  268.         break;
  269.  
  270.     case t_interval:
  271.         {
  272.         long val;
  273.  
  274.         if ((val = ivaltol(attr->value)) < 0) {
  275.             return xprintf(
  276.                    "%s: attribute %s: malformed interval value %s",
  277.                    fn, attr->name, attr->value);
  278.         }
  279.         conf_attr->uptr->v_long = val;
  280.         }
  281.         break;
  282.  
  283.     case t_double:
  284.         {
  285.         double val;
  286.         char c;            /* catch sscanf spill over */
  287.  
  288.         /* should be exactly one item set by sscanf */
  289.         if (sscanf(attr->value, "%lf%c", &val, &c) != 1) {
  290.             return xprintf(
  291.                   "%s: attribute %s: malformed floating number %s",
  292.                    fn, attr->name, attr->value);
  293.         }
  294.         conf_attr->uptr->v_double = val;
  295.         }
  296.         break;
  297.  
  298.     case t_proc:
  299. /*        if (error = conf_attr->uptr->v_proc(attr)) { */
  300.         if (error = (*((char *(*)())conf_attr->uptr))(attr)) {
  301.         return xprintf("%s: %s", fn, error);
  302.         }
  303.         break;
  304.  
  305.     case t_infoproc:
  306.         return xprintf("%s: %s: read-only attribute", fn, attr->name);
  307.  
  308.     default:
  309.         return xprintf("%s: %s: unknown attribute type", fn, attr->name);
  310.     }
  311.     }
  312.  
  313.     return NULL;
  314. }
  315.  
  316. /*
  317.  * print_config_variable - write the value for a config variable on stdout
  318.  */
  319. void
  320. print_config_variable(name)
  321.     char *name;
  322. {
  323.     struct attr_table *conf_attr;
  324.     char *value;
  325.  
  326.     if (EQ(name, "help")) {
  327.     print_config_help();
  328.     return;
  329.     }
  330.     if (EQ(name, "all")) {
  331.     print_config_all();
  332.     return;
  333.     }
  334.  
  335.     conf_attr = find_attribute(name, conf_attributes, end_conf_attributes);
  336.  
  337.     if (conf_attr == NULL && errfile) {
  338.     (void) fprintf(errfile, "%s: unknown attribute: %s\n", program, name);
  339.     return;
  340.     }
  341.     if (conf_attr == NULL) {
  342.     return;
  343.     }
  344.     switch (conf_attr->type) {
  345.     case t_string:
  346.     if (conf_attr->uptr->v_string) {
  347.         value = conf_attr->uptr->v_string;
  348.     } else {
  349.         value = "";
  350.     }
  351.     break;
  352.  
  353.     case t_boolean:
  354.     if (conf_attr->uptr->v_boolean) {
  355.         value = "true";
  356.     } else {
  357.         value = "false";
  358.     }
  359.     break;
  360.  
  361.     case t_char:
  362.     {
  363.         static char charv[2] = "x";
  364.  
  365.         charv[0] = conf_attr->uptr->v_char;
  366.         value = charv;
  367.     }
  368.     break;
  369.  
  370.     case t_int:
  371.     {
  372.         static char intv[20];
  373.  
  374.         (void) sprintf(intv, "%d", conf_attr->uptr->v_int);
  375.         value = intv;
  376.     }
  377.     break;
  378.  
  379.     case t_long:
  380.     {
  381.         static char longv[20];
  382.  
  383.         (void) sprintf(longv, "%ld", conf_attr->uptr->v_long);
  384.         value = longv;
  385.     }
  386.     break;
  387.  
  388.     case t_interval:
  389.     if ((value = ltoival(conf_attr->uptr->v_long)) == NULL) {
  390.         static char v[20];
  391.         sprintf(v, "%ld", conf_attr->uptr->v_long);
  392.         value = v;
  393.     }
  394.     break;
  395.  
  396.     case t_double:
  397.     {
  398.         static char doublev[20];
  399.  
  400.         (void) sprintf(doublev, "%g", conf_attr->uptr->v_double);
  401.         value = doublev;
  402.     }
  403.     break;
  404.  
  405.     case t_proc:
  406.     if (errfile) {
  407.         (void) fprintf(errfile, "%s: %s: cannot print proc attributes\n",
  408.                program, name);
  409.     }
  410.     return;
  411.  
  412.     case t_infoproc:
  413.     value = (*((char *(*)())conf_attr->uptr))();
  414.     break;
  415.  
  416.     default:
  417.     if (errfile) {
  418.         (void) fprintf(errfile, "%s: %s: unknown type\n");
  419.     }
  420.     return;
  421.     }
  422.     if (debug) {
  423.     (void) printf("%s=%s\n", name, value);
  424.     } else {
  425.     (void) printf("%s\n", value);
  426.     }
  427. }
  428.  
  429. /*
  430.  * print_config_help - output a listing of all config attributes, with type
  431.  */
  432. static void
  433. print_config_help()
  434. {
  435.     register struct attr_table *t;
  436.     register tup *last_uptr = NULL;
  437.  
  438.     for (t = conf_attributes; t < end_conf_attributes; t++) {
  439.     register char *typename;
  440.  
  441.     if (t->uptr == last_uptr) {
  442.         continue;
  443.     }
  444.     last_uptr = t->uptr;
  445.     switch(t->type) {
  446.     case t_string:  typename = "string";  break;
  447.     case t_boolean: typename = "boolean"; break;
  448.     case t_char:    typename = "char";    break;
  449.     case t_int:     typename = "int";     break;
  450.     case t_long:    typename = "long";    break;
  451.     case t_interval:typename = "interval";break;
  452.     case t_double:  typename = "double";  break;
  453.     case t_proc:    typename = "special"; break;
  454.     case t_infoproc:typename = "info";    break;
  455.     default:        typename = "unkown type";  break;
  456.     }
  457.     (void) printf("%s=%s\n", t->name, typename);
  458.     }
  459. }
  460.  
  461. /*
  462.  * print_config_all - print all config file variables
  463.  */
  464. static void
  465. print_config_all()
  466. {
  467.     register struct attr_table *t;
  468.     register tup *last_uptr = NULL;
  469.     int save_debug = debug;
  470.  
  471.     debug = 1;
  472.     for (t = conf_attributes; t < end_conf_attributes; t++) {
  473.     if (t->uptr == last_uptr) {
  474.         continue;
  475.     }
  476.     last_uptr = t->uptr;
  477.     switch(t->type) {
  478.     case t_string:
  479.     case t_boolean:
  480.     case t_char:
  481.     case t_int:
  482.     case t_long:
  483.     case t_interval:
  484.     case t_double:
  485.     case t_infoproc:
  486.         print_config_variable(t->name);
  487.         break;
  488.     default:
  489.         (void) printf("%s: unknown type\n", t->name);
  490.         break;
  491.     }
  492.     }
  493.     debug = save_debug;
  494. }
  495.  
  496.  
  497. /*
  498.  * read_standard_file - read (for example) a transport, director or router file
  499.  *
  500.  * given a template default structure, some information about that structure,
  501.  * and an attr_table describing attributes, read a file of standard
  502.  * attribute descriptions and return a list describing all of the entries
  503.  * in that file.
  504.  *
  505.  * inputs:
  506.  *    f          - open input file.  File format must conform to what is
  507.  *            expected by read_entry and parse_entry in parse.c.
  508.  *    template      - pointer to the template structure.
  509.  *    struct_size   - size of template structure.
  510.  *    name_offset   - offset to the name element in the template structure.
  511.  *    flags_offset  - offset to flags element of structure.
  512.  *    succ_offset   - offset to succ element of structure.
  513.  *    attr_table    - table defining generic attributes.
  514.  *    end_attr_table- end of the attribute table
  515.  *
  516.  *    driv_function - function to handle driver attributes for each entry.
  517.  *            Also, this function can check the validity of the
  518.  *            generic attributes in the passed structure.  The
  519.  *            function should return NULL, or an error message.
  520.  *            It is called as:
  521.  *
  522.  *                char *
  523.  *                f(s, d)
  524.  *                char *s;   --- structure being defined
  525.  *                struct attribute *d;  --- driver attributes
  526.  *
  527.  *            If driv_function is NULL, no driver attributes are
  528.  *            allowed and no function is called.
  529.  *    head          - pointer to a variable in which to store the head
  530.  *            of the generated structure list.
  531.  *
  532.  * output:
  533.  *    If an error occured, an error message will be returned.
  534.  *    Otherwise NULL will be returned and a pointer to the new
  535.  *    structure list will be stored at the location pointed to by
  536.  *    `head'.
  537.  */
  538. char *
  539. read_standard_file(f, template, struct_size,
  540.            name_offset, flags_offset, succ_offset,
  541.            attr_table, end_attr_table,
  542.            driv_function, head)
  543.     FILE *f;                /* input file */
  544.     register char *template;        /* template structure */
  545.     int struct_size;            /* size of template structure */
  546.     int name_offset;            /* name field offset in structure */
  547.     int flags_offset;            /* where to store boolean flags */
  548.     int succ_offset;            /* where to store succ pointer */
  549.     struct attr_table *attr_table;    /* start of attribute table */
  550.     struct attr_table *end_attr_table;    /* e.g., ENDTABLE(attr_table) */
  551.     char *(*driv_function)();        /* function to handle driver attrs */
  552.     char **head;            /* output structure list */
  553. {
  554.     char **link_ptr;            /* pointer to last succ element */
  555.     char *cur;                /* current structure to define */
  556.     char *s;                /* text for current entry */
  557.  
  558.     /* start out with no structure list entries */
  559.     link_ptr = head;
  560.     *link_ptr = NULL;
  561.  
  562.     /*
  563.      * scan through reading entries.  For each entry allocate a
  564.      * structure and fill it in.  Also, link the new structure to the
  565.      * previous structure.
  566.      */
  567.     while (s = read_entry(f)) {
  568.     char *error;
  569.     struct attribute *generic_attrs; /* generic attributes for entry */
  570.     struct attribute *driver_attrs;    /* driver attributes for entry */
  571.     char *name;            /* name of entry */
  572.  
  573.     /* create the new structure and forward link to it */
  574.     *link_ptr = cur = xmalloc(struct_size);
  575.     link_ptr = (char **)(cur + succ_offset);
  576.  
  577.     /* fill in the entry structure, starting with the template */
  578.     (void) memcpy(cur, template, struct_size);
  579.  
  580.     /* get all of the attributes */
  581.     name = parse_entry(s, &generic_attrs, &driver_attrs, &error);
  582.     if (name == NULL) {
  583.         return error;
  584.     }
  585.  
  586.     /* fill in the name */
  587.     *(char **)(cur + name_offset) = name;
  588.  
  589.     /*
  590.      * fill in the generic attributes, calling attr_function for
  591.      * attributes not in attr_table
  592.      */
  593.     error = fill_attributes(cur, generic_attrs,
  594.                 (long *)(cur + flags_offset),
  595.                 attr_table, end_attr_table);
  596.     if (error) {
  597.         return error;
  598.     }
  599.     if (driv_function) {
  600.         error = (*driv_function)(cur, driver_attrs);
  601.         if (error) {
  602.         return error;
  603.         }
  604.     } else if (driver_attrs) {
  605.         return xprintf("no driver attributes allowed in file");
  606.     }
  607.     }
  608.  
  609.     /* everything went okay */
  610.     return NULL;
  611. }
  612.  
  613.  
  614. /*
  615.  * fill_attributes - build a structure and fill in attributes
  616.  *
  617.  * Given a list of attributes extracted from one of the configuration
  618.  * files and an array of known attributes, fill in a stucture to which
  619.  * those attributes pertain.
  620.  *
  621.  * inputs:
  622.  *    sp          - pointer to stucture that is to be filled in
  623.  *    attrs          - list of given attributes
  624.  *    flags          - pointer to long where boolean flags should be OR'd in
  625.  *    attr_table    - table describing known attributes
  626.  *    end_attr_table- end of known attribies (i.e., ENDTABLE(attr_table))
  627.  *
  628.  * output:
  629.  *    returns either an error message, or NULL if everything went okay.
  630.  */
  631. char *
  632. fill_attributes(sp, attrs, flags, attr_table, end_attr_table)
  633.     char *sp;
  634.     struct attribute *attrs;
  635.     long *flags;
  636.     struct attr_table *attr_table;
  637.     struct attr_table *end_attr_table;
  638. {
  639.     char *error;
  640.  
  641.     /* step through all of the attributes from the file entry */
  642.     for (; attrs; attrs = attrs->succ) {
  643.     register struct attr_table *t;    /* table entry */
  644.     register char *value = attrs->value;
  645.  
  646.     /* find the attribute in the list of known attributes */
  647.     t = find_attribute(attrs->name, attr_table, end_attr_table);
  648.     if (t == NULL) {
  649.         /* didn't find the attribute */
  650.         return xprintf("%s: unknown attribute", attrs->name);
  651.     }
  652.  
  653.     /* what do with this attribute? */
  654.     if (t->type == t_boolean) {
  655.         /* make sure boolean types are given as booleans */
  656.         if (attrs->value != on && attrs->value != off) {
  657.         return xprintf("boolean attribute %s has non-boolean form",
  658.                    attrs->name);
  659.         }
  660.     } else {
  661.         if ((attrs->value == on &&
  662.          t->type != t_proc) ||
  663.         (attrs->value == off &&
  664.          t->type != t_string &&
  665.          t->type != t_int &&
  666.          t->type != t_long &&
  667.          t->type != t_interval &&
  668.          t->type != t_double &&
  669.          t->type != t_proc))
  670.         {
  671.         return xprintf("non-boolean attribute %s has boolean form",
  672.                    attrs->name);
  673.         }
  674.     }
  675.  
  676.     /* fill in the attribute */
  677.     switch (t->type) {
  678.     case t_string:
  679.         if (value == off) {
  680.         *(char **)(sp + t->offset) = NULL;
  681.         } else {
  682.         *(char **)(sp + t->offset) = value;
  683.         }
  684.         break;
  685.  
  686.     case t_boolean:
  687.         if (value == on) {
  688.         *flags |= t->offset;
  689.         } else {
  690.         *flags &= ~t->offset;
  691.         }
  692.         break;
  693.  
  694.     case t_char:
  695.         if (strlen(attrs->value) != 1) {
  696.         return xprintf("bad character constant for attribute %s",
  697.                    attrs->name);
  698.         }
  699.         *(sp + t->offset) = value[0];
  700.         break;
  701.  
  702.     case t_int:
  703.         error = NULL;
  704.         *(int *)(sp + t->offset) = (int)c_atol(value, &error);
  705.  
  706.         if (error) {
  707.         return xprintf("attribute %s: %s", attrs->name, error);
  708.         }
  709.         break;
  710.  
  711.     case t_long:
  712.         error = NULL;
  713.         *(long *)(sp + t->offset) = c_atol(value, &error);
  714.  
  715.         if (error) {
  716.         return xprintf("attribute %s: %s", attrs->name, error);
  717.         }
  718.         break;
  719.  
  720.     case t_interval:
  721.         {
  722.         long val;
  723.  
  724.         if ((val = ivaltol(value)) < 0) {
  725.             return xprintf("attribute %s: malformed interval value %s",
  726.                    attrs->name, value);
  727.         }
  728.         *(long *)(sp + t->offset) = val;
  729.         }
  730.  
  731.     case t_double:
  732.         {
  733.         double val;
  734.         char c;            /* catch sscanf spill over */
  735.  
  736.         /* should be exactly one item set by sscanf */
  737.         if (sscanf(value, "%lf%c", &val, &c) != 1) {
  738.             return xprintf(
  739.                   "attribute %s: malformed floating number %s",
  740.                    attrs->name, value);
  741.         }
  742.         *(double *)(sp + t->offset) = val;
  743.         }
  744.         break;
  745.  
  746.     case t_proc:
  747. /*        if (error = t->uptr->v_proc(sp, attrs)) { */
  748.         if (error = (*((char *(*)())t->uptr))(sp, attrs)) {
  749.         return error;
  750.         }
  751.     }
  752.     }
  753.  
  754.     return NULL;
  755. }
  756.  
  757. /*
  758.  * find_attribute - find an attribute within an attribute table
  759.  */
  760. struct attr_table *
  761. find_attribute(name, table, end)
  762.     register char *name;        /* name to search for */
  763.     register struct attr_table *table;    /* table to search in */
  764.     register struct attr_table *end;    /* end of table */
  765. {
  766.     while (table < end) {
  767.     if (EQ(name, table->name)) {
  768.         return table;
  769.     }
  770.     table++;
  771.     }
  772.     return NULL;
  773. }
  774.  
  775.  
  776. /*
  777.  * add_config_stat - add a new config file to config_stat_list
  778.  *
  779.  * Pass a filename plus a pointer to a stat structure or NULL.
  780.  */
  781. void
  782. add_config_stat(fn, statp)
  783.     char *fn;                /* name of file */
  784.     struct stat *statp;            /* stat of the file, or NULL */
  785. {
  786.     struct config_stat *new = (struct config_stat *)xmalloc(sizeof(*new));
  787.  
  788.     new->fn = COPY_STRING(fn);
  789.     if (statp) {
  790.     new->mtime = statp->st_mtime;
  791.     new->dev = statp->st_dev;
  792.     new->ino = statp->st_ino;
  793.     } else {
  794.     new->mtime = (time_t)0;
  795.     }
  796.     new->succ = config_stat_list;
  797.     config_stat_list = new;
  798. }
  799.  
  800. /*
  801.  * is_newconf - check if we have a new set of configuration files
  802.  *
  803.  * returns TRUE if a configuration fie has changed, FALSE otherwise
  804.  */
  805. int
  806. is_newconf()
  807. {
  808.     struct stat statbuf;
  809.     struct config_stat *csp;
  810.  
  811.     for (csp = config_stat_list; csp; csp = csp->succ) {
  812.     if (stat(csp->fn, &statbuf) < 0) {
  813.         if (csp->mtime != (time_t)0) {
  814.         /* file no longer exists */
  815.         return TRUE;
  816.         }
  817.     } else {
  818.         if (csp->mtime == (time_t)0) {
  819.         /* file now exists */
  820.         return TRUE;
  821.         }
  822.         if (csp->mtime != statbuf.st_mtime ||
  823.         csp->dev != statbuf.st_dev ||
  824.         csp->ino != statbuf.st_ino)
  825.         {
  826.         /* existing file has changed */
  827.         return TRUE;
  828.         }
  829.     }
  830.     }
  831.  
  832.     /* nothing has changed */
  833.     return FALSE;
  834. }
  835.  
  836. /*
  837.  * make_lib_fn - build a filename relative to the smail lib directory
  838.  *
  839.  * If the filename begins with '/' or is "-" return it unmodified.
  840.  * Return NULL if smail_lib_dir is undefined, or if the given
  841.  *  filename is NULL.
  842.  */
  843. char *
  844. make_lib_fn(fn)
  845.     char *fn;                /* filename to expand */
  846. {
  847.     if (fn == NULL) {
  848.     return NULL;
  849.     }
  850.     if (fn[0] == '/' || (fn[0] == '-' && fn[1] == '\0')) {
  851.     return fn;
  852.     }
  853.     if (smail_lib_dir == NULL) {
  854.     return NULL;
  855.     }
  856. #ifdef GLOTZNET
  857.     return xprintf("%s/%s/%s", smail_lib_dir, glotzhost, fn);
  858. #else /* GLOTZNET */
  859.     return xprintf("%s/%s", smail_lib_dir, fn);
  860. #endif /* GLOTZNET */
  861. }
  862.  
  863.  
  864. #ifdef    STANDALONE
  865.  
  866. #include "varargs.h"
  867.  
  868. struct transport *transports;
  869. struct director *directors;
  870. struct router *routers;
  871.  
  872. /*
  873.  * find_direct_driver - given a driver's name, return the driver structure
  874.  *
  875.  * return NULL if driver does not exist.
  876.  */
  877. struct direct_driver *
  878. find_direct_driver(name)
  879.     register char *name;        /* search key */
  880. {
  881. #ifdef    notyet
  882.     register struct direct_driver *ddp;    /* pointer to table of drivers */
  883.  
  884.     for (ddp = direct_drivers; ddp->name; ddp++) {
  885.     if (EQ(ddp->name, name)) {
  886.         return ddp;            /* found the driver */
  887.     }
  888.     }
  889.  
  890.     return NULL;            /* driver not found */
  891. #else    /* notyet */
  892.     static struct direct_driver dd = {
  893.     NULL, 1, NULL, NULL, NULL, NULL,
  894.     };
  895.  
  896.     return ⅆ
  897. #endif    /* notyet */
  898. }
  899.  
  900. /*
  901.  * find_transport_driver - given a driver's name, return the driver structure
  902.  *
  903.  * return NULL if driver does not exist.
  904.  */
  905. struct transport_driver *
  906. find_transport_driver(name)
  907.     register char *name;        /* search key */
  908. {
  909. #ifdef    notyet
  910.     register struct transport_driver *tdp; /* pointer to table of drivers */
  911.  
  912.     for (tdp = transport_drivers; tdp->name; tdp++) {
  913.     if (EQ(tdp->name, name)) {
  914.         return tdp;            /* found the driver */
  915.     }
  916.     }
  917.  
  918.     return NULL;            /* driver not found */
  919. #else    /* notyet */
  920.     static struct transport_driver td = {
  921.     NULL, 1, NULL, NULL, NULL, NULL,
  922.     };
  923.     return &td;
  924. #endif    /* notyet */
  925. }
  926.  
  927. /*
  928.  * find_route_driver - given a driver's name, return the driver structure
  929.  *
  930.  * return NULL if driver does not exist.
  931.  */
  932. struct route_driver *
  933. find_route_driver(name)
  934.     register char *name;        /* search key */
  935. {
  936. #ifdef    notyet
  937.     register struct route_driver *rdp;    /* pointer to table of drivers */
  938.  
  939.     for (rdp = route_drivers; rdp->name; rdp++) {
  940.     if (EQ(rdp->name, name)) {
  941.         return rdp;            /* found the driver */
  942.     }
  943.     }
  944.  
  945.     return NULL;            /* driver not found */
  946. #else    /* notyet */
  947.     static struct route_driver rd = {
  948.     NULL, 1, NULL, NULL, NULL, NULL,
  949.     };
  950.     return &rd;
  951. #endif    /* notyet */
  952. }
  953.  
  954. /*VARARGS2*/
  955. void
  956. panic(exitcode, fmt, va_alist)
  957.     int exitcode;            /* call exit(exitcode) */
  958.     char *fmt;                /* printf(3) format */
  959.     va_dcl                              /* arguments for printf */
  960. {
  961.     va_list ap;
  962.  
  963.     va_start(ap);
  964.     (void)fprintf(stderr, "PANIC(%s): ", exitcode);
  965.     (void)vfprintf(stderr, fmt, ap);
  966.     putc('\n', stderr);            /* fatal messages not \n terminated */
  967.     va_end(ap);
  968.  
  969.     return_to_sender = TRUE;
  970.     exit(exitcode);
  971. }
  972.  
  973. /*VARARGS2*/
  974. void
  975. write_log(log, fmt, va_alist)
  976.     int log;                /* TRUE if to write global log file */
  977.     char *fmt;                /* printf(3) format */
  978.     va_dcl                              /* arguments for printf */
  979. {
  980.     va_list ap;
  981.  
  982.     va_start(ap);
  983.     (void)fprintf(stderr, log? "PUBLIC: ": "PRIVATE: ");
  984.     (void)vfprintf(stderr, fmt, ap);
  985.     putc('\n', stderr);
  986.     va_end(ap);
  987. }
  988.  
  989. void
  990. main(argc, argv)
  991.     int argc;                /* count of arguments */
  992.     char *argv[];            /* vector of arguments */
  993. {
  994.     char *error;
  995.  
  996.     if (argc != 2) {
  997.     (void) fprintf(stderr, "Usage: %s config-file", argv[0]);
  998.     /*NOTREACHED*/
  999.     }
  1000.  
  1001.     config_file = argv[1];
  1002.     if ((error = read_config_file(config_file, CONFIG_PRIMARY)) ||
  1003.     (second_config_file &&
  1004.      error = read_config_file(second_config_file, CONFIG_SECONDARY))
  1005.     (error = read_transport_file()) ||
  1006.     (error = read_router_file()) ||
  1007.     (error = read_director_file()) ||
  1008.     (error = read_qualify_file()) ||
  1009.     (error = read_retry_file()))
  1010.     {
  1011.     (void) fprintf(stderr, "%s: %s\n", argv[0], error);
  1012.     }
  1013. }
  1014. #endif    /* STANDALONE */
  1015.